using System;
using System.Collections.Generic;
using CustomORM.Mapping;

namespace CustomORM.Repository
{
    public class Criteria
    {
        public List<CriteriaParticipant> Participants { get; set; }
        public List<Type> ParticipantTypes { get; set; }
        protected string AdditionalSqlText { get; set; }
        protected string CompleteSQL { get; private set; }
        public Dictionary<string, object> Parameters { get; private set; }

        public Criteria(Type entityType, string mainAlias)
        {
            Participants = new List<CriteriaParticipant>();
            ParticipantTypes= new List<Type>();
            Parameters = new Dictionary<string, object>();

            var criteriaParticipant = new CriteriaParticipant(entityType, mainAlias);
            ParticipantTypes.Add(entityType);
            Participants.Add(criteriaParticipant);
        }

        public Criteria AddEntity(Type entityType, string entityAlias)
        {
            var criteriaParticipant = new CriteriaParticipant(entityType, entityAlias);
            ParticipantTypes.Add(entityType);
            Participants.Add(criteriaParticipant);
            return this;
        }

        public string GenerateSelectForPart()
        {
            var participantsFields = new List<string>();
            foreach (var participant in Participants)
            {
                var participantFieldNames = participant.Mapper.GetFieldNamesForSql();
                var participantFieldNamesUnique = participant.Mapper.GetFieldNamesUniqueForSql();
                var fields = SqlBuilder.CommaSeparateFields(participantFieldNames, participant.Alias, participantFieldNamesUnique);
                participantsFields.Add(fields);
            }
            var selectFields = SqlBuilder.CommaSeparate(participantsFields);

            var headingParticipant = Participants[0];
            string selectHeader = SqlBuilder.FormatSelectHeader(selectFields, headingParticipant.Mapper.TableName, headingParticipant.Alias);
            return selectHeader;
        }

        public string GenerateCompleteSelect()
        {
            var selectHeader = GenerateSelectForPart();
            CompleteSQL = string.Format("{0}{1} ", selectHeader, AdditionalSqlText);
            return CompleteSQL;
        }

        public Criteria AddSQL(string sqlText, params object[] strParameters)
        {
            // Convert incoming parameters to make them compatible with SQL
            if(strParameters != null)
            {
                for (int i = 0; i < strParameters.Length; i++)
                {
                    if (strParameters[i] is DateTime)
                    {
                        var sqlFormattedDate = ((DateTime)strParameters[i]).ToString("yyyy-MM-dd HH:mm:ss");
                        strParameters[i] = sqlFormattedDate;
                    }
                }
            }

            AdditionalSqlText = string.Format(sqlText, strParameters);
            return this;
        }

        public Criteria AddParameter(string paramName, object paramValue)
        {
            Parameters[paramName] = paramValue;
            return this;
        }
        
    }

    public class CriteriaParticipant
    {
        public Type Type { get; set; }
        public IEntityToTableMapper Mapper { get; set; }
        public string Alias { get; set; }

        public CriteriaParticipant(Type type, string entityAlias)
        {
            Type = type;
            Alias = entityAlias;
            Mapper = MagicMapper.GetMapper(type);
        }
    }
}